package com.jimmy.medical.wechat;

import com.jimmy.medical.wechat.model.AccessTokenEntity;
import com.jimmy.medical.wechat.model.JsTicketEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

@Component
@Slf4j
public class WeChatAccessTokenTask {

	private static final String TAG = WeChatAccessTokenTask.class.getName();

	private int retryCount = 0;
	private int retryJsTicketCount = 0;
	/**周期工作状态*/
	private boolean isScheduleOn = false;
	/**首次刷新*/
	private boolean isFirstGet = false;
	/**周期2小时*/
	private long PERIOD_OF_TASK = 60*60*2;
	/**周期线程池*/
	ScheduledExecutorService  scheduledThreadExecutor = Executors.newScheduledThreadPool(2);
	/**单线程池*/
	ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();

	@Autowired
	WeChatHttp weChatHttp;

	@Autowired
	WeChatAccessToken weChatAccessToken;

	private static WeChatAccessTokenTask INSTANCE = new WeChatAccessTokenTask();

	private WeChatAccessTokenTask() {}

	public final WeChatAccessTokenTask getInstance() {
		return INSTANCE;
	}
	
	public synchronized void begin(){
		if(isFirstGet == false){
			isFirstGet = true;
			singleThreadExecutor.execute(new AskTokenThread());
		}
	}
	
	public synchronized void getJsTicket(){
		JsTicketEntity jsTicket = weChatHttp.getAPIJSTicket(weChatAccessToken.getAccessToken());
		if(jsTicket != null && !StringUtils.isEmpty(jsTicket.getTicket())){
			//设置全局token
			weChatAccessToken.setJsTicket(jsTicket.getTicket());
			weChatAccessToken.setJsTicketExpiresIn(jsTicket.getExpiresIn());
		}else{
			if(jsTicket == null){
				log.info(TAG, "!!!!--->>> get getAPIJSTicket failed : null JsTicketEntity");
			}else{
				log.info(TAG, "!!!!--->>> get getAPIJSTicket failed :("+ jsTicket.getErrCode()+")"+jsTicket.getErrMsg());
			}
			singleThreadExecutor.execute(new JsTicketThread(weChatAccessToken.getAccessToken()));
		}
	}
	
	private synchronized void beginTask(long delyTime){
		//提前10分钟刷新；
		delyTime = delyTime - 60*10;
		//立即刷新
		if(delyTime <= 0){
			delyTime = 1;
		}
		try{
			//周期2小时
			scheduledThreadExecutor.scheduleAtFixedRate(new AskTokenThread(), delyTime, PERIOD_OF_TASK, TimeUnit.SECONDS);
			//周期工作状态开启
			isScheduleOn = true;
			log.info(TAG, "get APIAccessToken scheduleAtFixedRate success--------");
		}catch (Exception e) {
			e.printStackTrace();
			isScheduleOn = false;
			log.info(TAG, "get APIAccessToken scheduleAtFixedRate failed--------");
		}
	}
	
	public void stopTask(){
		scheduledThreadExecutor.shutdown();
		isScheduleOn = false;
	}
	
	class AskTokenThread implements Runnable{
		
		public AskTokenThread(){
			retryCount = 0;
			log.info(TAG, "begin get APIAccessToken --------");
		}
		
		public void run() {
			try{
				log.info(TAG, "http get start --------");
				AccessTokenEntity tokenRst = weChatHttp.getAPIAccessToken();
				//解析结果success:{"access_token":"ACCESS_TOKEN","expires_in":7200} failed:{"errcode":40013,"errmsg":"invalid appid"}
				if(tokenRst != null && !StringUtils.isEmpty(tokenRst.getAccessToken())){
					log.info(TAG, "get APIAccessToken Success -->> access_token:"+tokenRst.getAccessToken() + " expires_in:"+tokenRst.getExpiresIn());
					//设置全局token
					weChatAccessToken.setAccessToken(tokenRst.getAccessToken());
					weChatAccessToken.setExpiresIn(tokenRst.getExpiresIn());
					//获取JS TICKET
					singleThreadExecutor.execute(new JsTicketThread(tokenRst.getAccessToken()));
					//开启周期刷新
					if(isScheduleOn == false){
						beginTask(weChatAccessToken.getExpiresIn());
					}
				}else{
					if(tokenRst == null){
						log.info(TAG, "!!!!--->>> get APIAccessToken failed : null AccessTokenEntity");
					}else{
						log.info(TAG, "!!!!--->>> get APIAccessToken failed :("+ tokenRst.getErrCode()+")"+tokenRst.getErrMsg());
					}
					retry();
				}
//				JSONObject jsonToken = WeixinHttp.getAPIAccessTokenJson();
//				//解析结果success:{"access_token":"ACCESS_TOKEN","expires_in":7200} failed:{"errcode":40013,"errmsg":"invalid appid"}
//				if(jsonToken.containsKey("access_token")){
//					WXLog.Log(TAG, "get APIAccessToken Success:"+jsonToken);
//					//设置全局token
//					WXAccessTokenUtils.setAccessToken(jsonToken.getString("access_token"));
//					WXAccessTokenUtils.setExpiresIn(jsonToken.getLongValue("expires_in"));
//					//开启周期刷新
//					if(isScheduleOn == false){
//						beginTask(WXAccessTokenUtils.getExpiresIn());
//					}
//				}else{
//					WXLog.Log(TAG, "!!!!--->>> get APIAccessToken failed :"+jsonToken);
//					retry();
//				}
			}catch (Exception e) {
				e.printStackTrace();
				retry();
			}
		}
		
		private void retry(){
			//重新获取
			if(retryCount < 3){
				log.info(TAG, "retry get APIAccessToken ("+retryCount+")--------");
				singleThreadExecutor.execute(this);
			//超过3次未能启动成功，则设置为关闭状态	
			}else if(isScheduleOn == false){
				isFirstGet = false;
				log.info(TAG, "retry get APIAccessToken failed with no schedul task!--------");
			}else{
				log.info(TAG, "retry get APIAccessToken failed with schedul task on!--------");
			}
			retryCount ++;
		}

	}
	
	class JsTicketThread implements Runnable{

		private String accessToken;
		
		public JsTicketThread(String accessToken) {
			super();
			retryJsTicketCount = 0;
			this.accessToken = accessToken;
		}

		public void run() {
			JsTicketEntity jsTicket = weChatHttp.getAPIJSTicket(accessToken);
			if(jsTicket != null && !StringUtils.isEmpty(jsTicket.getTicket())){
				//设置全局token
				weChatAccessToken.setJsTicket(jsTicket.getTicket());
				weChatAccessToken.setJsTicketExpiresIn(jsTicket.getExpiresIn());
			}else{
				if(jsTicket == null){
					log.info(TAG, "!!!!--->>> get getAPIJSTicket failed : null JsTicketEntity");
				}else{
					log.info(TAG, "!!!!--->>> get getAPIJSTicket failed :("+ jsTicket.getErrCode()+")"+jsTicket.getErrMsg());
				}
				retryJsTicket();
			}
		}
		
		private void retryJsTicket(){
			//重新获取
			if(retryJsTicketCount < 3){
				log.info(TAG, "retry get APIJsTicket ("+retryJsTicketCount+")--------");
				singleThreadExecutor.execute(this);
				//超过3次未能启动成功，则设置为关闭状态	
			}else if(isScheduleOn == false){
				isFirstGet = false;
				log.info(TAG, "retry get APIJsTicket failed with no schedul task!--------");
			}else{
				log.info(TAG, "retry get APIJsTicket failed with schedul task on!--------");
			}
			retryJsTicketCount ++;
		}
	}
}
